package config

import (
	"fmt"
	"reflect"
)

type elemFlagConfig struct {
	cfgPath  string
	cmdPath  string
	flagName string
}

type RendererFlag struct {
	sort int

	elems []elemFlagConfig

	lookup FlagLookupFunc
}

func NewRendererFlag(sort int) *RendererFlag {
	return &RendererFlag{
		sort:  sort,
		elems: make([]elemFlagConfig, 0, 8),
	}
}

func (r *RendererFlag) Name() string {
	return "env"
}

func (r *RendererFlag) Sort() int {
	return r.sort
}

func (r *RendererFlag) Render(body reflect.Value, desc *ConfigDesc) error {
	if r.lookup == nil {
		return nil
	}

	for _, elem := range r.elems {
		if err := r.parseFlagElem(body, desc, elem); err != nil {
			return err
		}
	}
	return nil
}

type FlagLookupFunc func(cmdPath string, flagName string) (string, bool)

func (r *RendererFlag) SetLookupFunc(lookup FlagLookupFunc) {
	r.lookup = lookup
}

func (r *RendererFlag) parseFlagElem(body reflect.Value, desc *ConfigDesc, elem elemFlagConfig) error {
	flagVal, ok := r.lookup(elem.cmdPath, elem.flagName)
	if !ok {
		//没设置flag, 不要了
		return nil
	}

	rv, err := findFieldInBody(body, desc, elem.cfgPath)
	if err != nil {
		return err
	}
	if rv.Kind() == reflect.Invalid {
		return nil
	}

	if err := setValueFromString(rv, flagVal); err != nil {
		return fmt.Errorf("config: set flag [%s] value [%s] to [%s] failed: %v", elem.flagName, flagVal, elem.cfgPath, err)
	}

	return nil
}

func (r *RendererFlag) BindFlag(cfgPath, cmdPath, flagName string) {
	elem := elemFlagConfig{
		cfgPath:  cfgPath,
		cmdPath:  cmdPath,
		flagName: flagName,
	}
	r.elems = append(r.elems, elem)
}
